import React from 'react';
import _ from 'underscore';

import { fromJS, is } from 'immutable';
import { Scope } from 'lib/scopeFactory';

import { defaultApi } from '../../apis/core-util';

// 表示各种属性可能出现的操作集合。
const funcs = {
  number: [
    {
      label: '等于',
      value: 'equal',
      valueType: 'input'
    }, {
      label: '大于',
      value: 'greater',
      valueType: 'input'
    }, {
      label: '小于',
      value: 'less',
      valueType: 'input'
    }, {
      label: '区间',
      value: 'between',
      valueType: 'input-group'
    }
  ],
  string: [
    {
      label: '等于',
      value: 'equal',
      valueType: 'select'
    }, {
      label: '不等于',
      value: 'notEqual',
      valueType: 'select'
    }, {
      label: '包含',
      value: 'contain',
      valueType: 'single-select'
    }, {
      label: '不包含',
      value: 'notContain',
      valueType: 'single-select'
    }, {
      label: '正则匹配',
      value: 'rlike',
      valueType: 'input'
    }, {
      label: '正则不匹配',
      value: 'notrlike',
      valueType: 'input'
    }, {
      label: '有值',
      value: 'isSet',
      valueType: ''
    }, {
      label: '没值',
      value: 'notSet',
      valueType: ''
    }
  ],
  bool: [
    {
      label: '为真',
      value: 'isTrue',
      valueType: ''
    }, {
      label: '为假',
      value: 'isFalse',
      valueType: ''
    }
  ],
  list: [
    {
      label: '包含',
      value: 'in',
      valueType: 'single-select'
    }
  ]
}; // funcs

const convertValueToView = (condition, func) => {
  if (func.valueType === 'select' || func.valueType === 'single-select') {
    return _.map(condition.params, item => ({
      label: item,
      value: item
    }));
  } else if (func.valueType === 'input') {
    return condition.params[0];
  } else if (func.valueType === 'input-group') {
    return {
      left: condition.params[0],
      right: condition.params[1]
    };
  } else if (func.valueType === '') {
    return Infinity;
  }
  // TODO: other valueType need to add.
}; // convertValueToView

export default class SettingScope extends Scope {
  constructor(props, context) {
    super(props, context);

    this.props = props;
    this.isNew = props.isNew;
    this.__item = fromJS(props.item);
    this.$state = {
      target: _.defaults(props.item, {
        filters: []
      }),
      properties: []
    }; //$state

    this.propertiesApi = defaultApi({
      __url: () => `sd/${ BlueWare.appId }/api/event/${this.$state.target.predefinedEvent.object.id}/properties`
    });
  }

  $receive(nextProps) {
    let item = fromJS(nextProps.item);
    if (is(this.__item, item)) {
      return;
    }
    this.__item = item;

    this.$state.target = _.defaults(nextProps.item, {
      filters: []
    });

    if (nextProps.item && nextProps.item.event_name) {
      this.$state.target.predefinedEvent = _.find(nextProps.predefinedEvents,
        item => item.value.toLowerCase() === nextProps.item.event_name.toLowerCase());
    }

    if (this.$state.target.predefinedEvent &&
        this.$state.target.predefinedEvent.object.id !== undefined &&
        !this.$state.properties.length) {
      this.fetch();
    }
  } // $receive

  $load_properties(payload) {
    // 更换预定义事件时，应该清除与之关联的筛选器：因为新的预定义事件的属性和当前的不相同。
    _.extend(this.$state.target, {
      predefinedEvent: payload.item,
      filters: []
    });

    // 更新传入参数的事件名称。
    this.viewInstance.props.item.event_name = payload.item.value;

    // 重新获取新的预定义事件属性前，应该清除现有预定义事件的属性集合：因为新的预定义事件的属性和当前的不相同。
    this.$state.properties = [];
    this.fetch();
  } // $load_properties

  $add_item() {
    // 1. 只有选中了一个预定义的事件后，才能添加限制条件。
    // 2. 必须等待新预定义事件的属性取回后，才可以添加限制条件；否则没有可下拉的选项。
    if (!this.$state.target.predefinedEvent || !this.$state.properties.length) {
      return;
    }

    let defaultItem = this.$state.properties[0];
    this.$state.target.filters.push(
      _.extend(this.fillFunc(funcs[defaultItem.object.data_type][0]), {
        field: defaultItem,
        funcs: funcs[defaultItem.object.data_type]
      })
    );

    // 新添加的筛选器，可能导致窗口溢出、显示不全，所以这里需要提醒父窗口重绘。
    // 因为父窗口的重绘，所以这里省略 this.emit() 方法的调用。
    this.viewInstance.props.onNeedResize();
  } // $add_item

  $field_changed(payload) {
    let currentItem = this.$state.target.filters[payload.index];
    if (currentItem) {
      _.extend(currentItem, this.fillFunc(funcs[payload.item.object.data_type][0]), {
        field: payload.item,
        funcs: funcs[payload.item.object.data_type]
      });
      this.emit();
    }
  } // $field_changed

  fillFunc(func) {
    return {
      func,
      filter: func.valueType === '' ? Infinity : null
    };
  } // fillFunc

  $func_changed(payload) {
    let currentItem = this.$state.target.filters[payload.index];
    if (currentItem) {
      _.extend(currentItem, this.fillFunc(payload.item));
      this.emit();
    }
  } // $func_changed

  $filter_changed(payload) {
    let currentItem = this.$state.target.filters[payload.index];
    if (currentItem) {
      _.extend(currentItem, {
        filter: payload.item
      });
      this.emit();
    }
  } // $filter_changed

  $remove_filter(payload) {
    this.$state.target.filters = [
      ...this.$state.target.filters.slice(0, payload.index),
      ...this.$state.target.filters.slice(payload.index + 1)
    ];
    this.emit();
  } // $remove_filter

  convertCurrentSetting() {
    let target = this.$state.target;

    let filters = _.map(target.filter.conditions, item => {
      let fieldName = item.field.substring(item.field.lastIndexOf('.') + 1);
      let field = _.find(this.$state.properties, inner => inner.value === fieldName);

      let currentFuncs = funcs[field.object.data_type];
      let func = _.find(currentFuncs, inner => inner.value === item.function);
      let filter = convertValueToView(item, func);
      return {
        field,
        func,
        funcs: currentFuncs,
        filter
      };
    }, this);

    this.$state.target.filters = filters;
  } // convertCurrentSetting

  fetch() {
    this.propertiesApi
        .fetch()
        .fail(() => this.$state.properties = [])
        .done(data => {
          this.$state.properties = data.event.map(item => ({
            label: item.cname,
            value: item.name,
            object: item
          }));

          if (!this.isNew) {
            this.convertCurrentSetting();
          }
        })
        .always(() => {
          this.viewInstance.props.onNeedResize();
        });
  } // fetch

  $load() {
    let item = this.__item.toJS();
    if (item && item.event_name) {
      this.$state.target.predefinedEvent = _.find(this.viewInstance.props.predefinedEvents,
        p => p.value.toLowerCase() === item.event_name.toLowerCase());
    }

    if (this.$state.target.predefinedEvent &&
        this.$state.target.predefinedEvent.object.id !== undefined &&
        !this.$state.properties.length) {
      this.fetch();
    }
  } // $load
}
